//
// Created by hugan on 2020/11/16.
//
#include "../hardware/BatteryUtil.h"
#include "../hardware/VolumeUtil.h"
#include "../common/CommonUtil.h"
#include "../common/ShellExecuteUtil.h"
#include "../common/CharsetConverter.h"
#include  <direct.h>
#include  <stdio.h>

using namespace std;

void getBatteryInfo() {
    cout << "isAcOnline=" << BatteryUtil::isAcOnline() << endl;
    cout << "BatteryValue=" << BatteryUtil::getBatteryValue() << endl;
}

void testVolumeUtil() {
    VolumeUtil volumeUtil;
    cout << "volume=" << volumeUtil.getVolume() << endl;
    cout << "isMute=" << volumeUtil.isMute() << endl;
    volumeUtil.setMute(false);
    Sleep(800);
    volumeUtil.setMute(true);
    Sleep(800);

    int totalTime = 3000;
    for (int i = 0; i <= 100; ++i) {
        volumeUtil.setVolume(i);
        Sleep(totalTime / 100);
    }
    volumeUtil.setVolume(30);
//    /*测试CoInitialize,CoUninitialize是否有未知坑,没发现问题
    VolumeUtil volumeUtil2;
    cout << "volume=" << volumeUtil2.getVolume() << endl;
    cout << "isMute=" << volumeUtil2.isMute() << endl;/**/
}

void testVolumeUser32() {
    //无效
//    SendMessageW((HWND) nullptr, WM_APPCOMMAND, (WPARAM) nullptr, (LPARAM) APPCOMMAND_VOLUME_UP);
    SendMessageW((HWND) nullptr, WM_APPCOMMAND, (WPARAM) nullptr, (LPARAM) APPCOMMAND_VOLUME_MUTE);
}

/**
 * SendInput会受UIPI机制限制
 */
void testSendKeyEvent() {
//    cout << "res=" << CommonUtil::activeKeys(vector<WORD>{VK_LWIN, 'E'}) << endl;
//    cout << "res=" << CommonUtil::activeKeys(vector<WORD>{VK_CONTROL, VK_MENU, VK_TAB}) << endl;
//    cout << "res=" << CommonUtil::activeKeys(vector<WORD>{VK_LEFT}) << endl;
//    cout << "res=" << CommonUtil::activeKeys(vector<WORD>{VK_CONTROL, VK_LEFT}) << endl;
//shift+方向键
//    cout << "res=" << CommonUtil::activeKeys(vector<WORD>{VK_SHIFT, VK_LEFT}) << endl;//NumPad打开时,预期功能异常
//左右按键,
//    cout << "res=" << CommonUtil::activeKeys(vector<WORD>{VK_LSHIFT}) << endl;//java监听结果不能区分左右
//    cout << "res=" << CommonUtil::activeKeys(vector<WORD>{VK_RSHIFT}) << endl;//java监听结果不能区分左右
//媒体键
//    cout << "res=" << CommonUtil::activeKeys(vector<WORD>{VK_VOLUME_MUTE}) << endl;
//    cout << "res=" << CommonUtil::activeKeys(vector<WORD>{VK_MEDIA_PLAY_PAUSE}) << endl;
    cout << "res=" << CommonUtil::activeKeys(vector<WORD>{VK_MEDIA_STOP}) << endl;
    //cout << "res=" << CommonUtil::activeKeys(vector<WORD>{0xB2}) << endl;


    //keybd_event('E',
    //            0x45,
    //            KEYEVENTF_EXTENDEDKEY | 0,
    //            0);
    //Sleep(3000);
    //keybd_event('E',
    //            0x45,
    //            KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP,
    //            0);
}

/**
 * 测试模拟鼠标滚轮
 */
void testSendMouseWheel() {
    Sleep(800);

    HWND currentWindow = GetForegroundWindow();
    TCHAR pTitle[255];
    GetWindowText(currentWindow, pTitle, 255);
    cout << "currentWindow=" << pTitle << endl;

//    cout << "use:mouse_event" << endl;
//    mouse_event(MOUSEEVENTF_WHEEL, 0, 0, 300, 0);
//    Sleep(800);
//    mouse_event(MOUSEEVENTF_WHEEL, 0, 0, -300, 0);

    cout << "use:SendInput" << endl;
    INPUT inputs[1];
    inputs[0].type = INPUT_MOUSE;
    inputs[0].mi = {
            0, 0,
//            WHEEL_DELTA, MOUSEEVENTF_WHEEL,//上
//            static_cast<DWORD>(-WHEEL_DELTA), MOUSEEVENTF_WHEEL,//下
            static_cast<DWORD>(-WHEEL_DELTA), 0x01000,//左
//            WHEEL_DELTA, 0x01000,//右
    };
    SendInput(1, inputs, sizeof(INPUT));
}

void testShellExecute() {
//    ShellExecute(nullptr, "open", "C:/Windows/System32/taskmgr.exe", nullptr, nullptr, SW_SHOWNORMAL);
//    ShellExecute(nullptr, "open", "C:/Windows/System32/taskmgr.exe", nullptr, nullptr, SW_SHOWMINIMIZED);
    ShellExecute(nullptr, "open", "C:/Windows/System32/taskmgr.exe", nullptr, nullptr, SW_SHOWMAXIMIZED);
    ShellExecute(nullptr, "open", "C:/Windows/System32/taskmgr.exe", nullptr, nullptr, SW_SHOWMAXIMIZED);
}

void testShellExecuteUtil() {
    TCHAR tempPath[MAX_PATH];
    GetModuleFileName(nullptr, tempPath, MAX_PATH);
    string root = tempPath;
    //xxx\hup-utils-parent-cpp\cmake-build-release\CommonTest.exe
    int indexOf = root.find_last_of('\\', root.find_last_of('\\') - 1);//得到上两级目录
    root = root.substr(0, indexOf);
    cout << "root=" << root << endl;

    string targets[][2] = {
            {"\\testFiles\\enDir",       ""},
            {"\\testFiles\\中文目录",        ""},
            {"\\testFiles\\enFile.xlsx", "\\testFiles\\"},
            {"\\testFiles\\中文名.xlsx",    "\\testFiles\\"},
            {"\\testFiles\\中文目录",        ""},
    };

    int i = 0;
    for (auto &target :targets) {
        cout << "i=" << i << endl;
        string filePath = targets[i][0].insert(0, root);
        string ansiFile;
        CharsetConverter::utf82ansi(filePath, ansiFile);

        const char *dir = nullptr;
        string ansiDir;//不能放在if里面,否则if后被回收内存,导致dir是错误! 错误与char[2]="1234"是一个原理
        if (!targets[i][1].empty()) {
            string temp = targets[i][1].insert(0, root);
            CharsetConverter::utf82ansi(temp, ansiDir);
            dir = ansiDir.c_str();
        }
        cout << "ansiFile=" << ansiFile << endl;
        cout << "ansiDir=" << ansiDir << endl;
        int res = ShellExecuteUtil::open(ansiFile.c_str(), dir, nullptr);
        ShellExecuteUtil::printOpenRes(res);
        i++;
    }
}

/**
 * 媒体键,结果:无作用
 */
void testMediaPlay() {
//    SendMessage(nullptr, WM_APPCOMMAND, 0, APPCOMMAND_MEDIA_PLAY);
//    SendMessage(nullptr, WM_APPCOMMAND, 0, APPCOMMAND_MEDIA_PAUSE);
//    SendMessage(HWND_BROADCAST, WM_APPCOMMAND, 0, APPCOMMAND_MEDIA_PLAY);
    SendMessage(nullptr, WM_APPCOMMAND, 0x200eb0, APPCOMMAND_VOLUME_MUTE * 0x10000);
}

void testWindowScroll() {
    POINT mouseLoc;
    GetCursorPos(&mouseLoc);
    cout << "mouseLoc=" << mouseLoc.x << "," << mouseLoc.y << endl;

    HWND hwnd = WindowFromPoint(mouseLoc);
//    string title;
//    ::GetWindowTextA(hwnd, title, MAX_PATH);
//    cout << "title=" << title << endl;
//    ScrollWindow(hwnd, 110, -110, nullptr, nullptr);
//    GetWindowThreadProcessId()
}

/**
 * 获取键盘灯状态
 * https://www.cnblogs.com/llguanli/p/8427384.html
 */
void testKeyboardState(int mode) {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wmissing-noreturn"
    while (1) { // NOLINT(modernize-use-bool-literals)
        bool numOn = false;
        bool capsOn = false;
        bool scrollOn = false;
        if (mode == 1) {
            /*
             * 不可行!!
             * 获取的是进程启动时的状态, 轮询时不会更新结果
             */
            BYTE keyState[256];
            GetKeyboardState((LPBYTE) &keyState);
            numOn = keyState[VK_NUMLOCK] & 1;
            capsOn = keyState[VK_CAPITAL] & 1;
            scrollOn = keyState[VK_SCROLL] & 1;
        } else if (mode == 2) {
            //低位: 开关状态
            numOn = GetKeyState(VK_NUMLOCK) & 0x0001;
            capsOn = GetKeyState(VK_CAPITAL) & 0x0001;
            scrollOn = GetKeyState(VK_SCROLL) & 0x0001;
            //高位: 按下状态
            //numOn = GetKeyState(VK_NUMLOCK) & 0x8000;
            //capsOn = GetKeyState(VK_CAPITAL) & 0x8000;
            //scrollOn = GetKeyState(VK_SCROLL) & 0x8000;
        }
        byte state = (byte) (((scrollOn ? 1 : 0) << 2) | ((capsOn ? 1 : 0) << 1) | (numOn ? 1 : 0));
        cout << "numOn=" << numOn << ", capsOn=" << capsOn << ", scrollOn=" << scrollOn << ", state="
             << static_cast<int>(state) << ", mode=" << mode << endl;

        Sleep(1000);
    }
#pragma clang diagnostic pop
}

/**
 * 显示鼠标光标
 */
void testMouseCursor() {
    /*
     * 解决开机/重新登陆时,不移动物理鼠标时,系统不显示光标
     * 原因是,系统认为用户[正在使用触摸代替鼠标]
     *   GetCursorInfo 返回鼠标状态是[CURSORINFO.flags=2/被抑制]
     *   https://learn.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-cursorinfo
     *
     * 解决:使用SendInput移动一次鼠标即可恢复显示
     * https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-sendinput
     * https://stackoverflow.com/questions/54065974/restore-suppressed-cursor-after-touch-injection
     * https://social.technet.microsoft.com/Forums/en-US/3d6adcca-431b-4341-b2cc-f82f1ca8e1f9/how-to-disable-cursor-suppression-on-touch-input-on-windows-10
     * https://qa.1r1g.com/sf/ask/3431884501/
     */
    bool res;
    CURSORINFO info;
    info.cbSize = sizeof(info);
    res = GetCursorInfo(&info);
    cout << "GetCursorInfo.res=" << res << endl;
    cout << "info=" << info.cbSize << ", flags=" << info.flags << endl;
    cout << "ptScreenPos=" << info.ptScreenPos.x << "," << info.ptScreenPos.y << endl;

    INPUT inputs[1];
    inputs[0].type = INPUT_MOUSE;
    inputs[0].mi = {
            100, 0,
            0, MOUSEEVENTF_MOVE
    };
    res = SendInput(1, inputs, sizeof(INPUT));
    cout << "SendInput.res=" << res << endl;

    //使用ShowCursor: 实际是无效的,即使displayCounter>1
    //int displayCounter;
    //displayCounter = ShowCursor(true);
    //cout << "displayCounter=" << displayCounter << endl;

    res = GetCursorInfo(&info);
    cout << "GetCursorInfo.res=" << res << endl;
    cout << "info=" << info.cbSize << ", flags=" << info.flags << endl;
    cout << "ptScreenPos=" << info.ptScreenPos.x << "," << info.ptScreenPos.y << endl;
}

int main() {
    cout << "main.st" << endl;

//    getBatteryInfo();
//    testVolumeUtil();
//    testVolumeUser32();
//    testSendKeyEvent();
//    testSendMouseWheel();
//    testShellExecute();
//    testShellExecuteUtil();
//    testMediaPlay();
//    testWindowScroll();
    testKeyboardState(2);
//    testMouseCursor();

    cout << "main.ed" << endl;
    return 0;
}